package com.zzl.bonds.ticket.untils;

import com.alibaba.fastjson.JSON;
import com.zzl.bonds.ticket.constant.status.ApproveStatusEnum;
import com.zzl.bonds.ticket.constant.status.TicketStatusEnum;
import com.zzl.bonds.ticket.dto.KeyValue;
import com.zzl.bonds.ticket.exception.SysExceptionEnum;
import com.zzl.bonds.ticket.exception.SysExceptionFactory;
import com.zzl.general.common.constant.Constant;
import com.zzl.general.common.exception.SysException;
import com.zzl.general.common.serurity.entity.MenuInfo;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Nullable;
import javax.servlet.http.HttpSession;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

import static com.zzl.bonds.ticket.exception.SysExceptionEnum.TICKET_OBJECT_NO_ID_METHOD_METHOD;

/**
 * 票据工具类
 *
 * @author : spp
 * @date : 2022/2/18 13:34
 */
public class TicketUtils {

    private static final String GET_ID_METHOD_NAME = "getId";
    private static final String GET_TICKET_STATUS_METHOD_NAME = "getTicketStatus";
    private static final String GET_APPROVE_STATUS_METHOD_NAME = "getApproveStatus";
    private static final String GET_FROZEN_STATE_METHOD_NAME = "getFrozenState";


    private static final String SET_HAND_STATUS_METHOD_NAME = "setHandStatus";
    private static final String SET_HAND_PROGRESS_METHOD_NAME = "setHandProgress";

    private static final String SET_HAND_STATUS_INFO_METHOD_NAME = "setHandStatusInfo";

    private static final String SET_OPERATE_BUTTON_METHOD_NAME = "setOperateButton";

    /**
     * 获取票据对象的 字段值
     *
     * @param ticket 票对象
     * @return 对象值
     */
    public static TicketStatusEnum getTicketStatus(@NotNull Object ticket) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, GET_TICKET_STATUS_METHOD_NAME);
        if (!ObjectUtils.isEmpty(method)) {
            Object status = ReflectionUtils.invokeMethod(method, ticket);
            if (ObjectUtils.isEmpty(status)) {
                throw new SysException("票据状态为空");
            }
            if (status instanceof Integer) {
                return TicketStatusEnum.getStatus((Integer) status);
            } else {
                return TicketStatusEnum.getStatus(Integer.valueOf(status.toString()));
            }
        } else {
            throw new SysException("未找到票据的 getTicketStatus 方法");
        }

    }


    /**
     * 获取票据对象的 字段值
     *
     * @param ticket 票对象
     * @return 对象值
     */
    public static Integer getFrozenState(@NotNull Object ticket) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, GET_FROZEN_STATE_METHOD_NAME);
        if (!ObjectUtils.isEmpty(method)) {
            Object status = ReflectionUtils.invokeMethod(method, ticket);
            if (ObjectUtils.isEmpty(status)) {
                throw new SysException("票据 冻结状态为空");
            }
            return (Integer) status;
        } else {
            throw new SysException("未找到票据的 getFrozenState 方法");
        }
    }
    /**
     * 处理票据处理进度，如1/4
     *
     * @param ticket     票据对象
     * @param handStatus 处理状态
     * @throws SysException 业务异常
     */
    public static void setHandProgress(@NotNull Object ticket, Integer handStatus) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, SET_HAND_PROGRESS_METHOD_NAME, Integer.class);
        if (!ObjectUtils.isEmpty(method)) {
            ReflectionUtils.invokeMethod(method, ticket, handStatus);

        } else {
            throw new SysException("未找到开立票据的 setHandProgress 方法");
        }
    }
    /**
     * 处理票据处理状态，成功、开立中、失败
     *
     * @param ticket     票据对象
     * @param handStatus 处理状态
     * @throws SysException 业务异常
     */
    public static void setHandStatus(@NotNull Object ticket, String handStatus) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, SET_HAND_STATUS_METHOD_NAME, String.class);
        if (!ObjectUtils.isEmpty(method)) {
            ReflectionUtils.invokeMethod(method, ticket, handStatus);

        } else {
            throw new SysException("未找到开立票据的 setHandStatus 方法");
        }
    }

    /**
     * 设置票据处理状态详细描述，如已签收、内部复核中、收单企业签收中
     *
     * @param ticket     票据对象
     * @param handStatus 处理状态
     * @throws SysException 业务异常
     */
    public static void setHandStatusInfo(@NotNull Object ticket, String handStatus) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, SET_HAND_STATUS_INFO_METHOD_NAME, String.class);
        if (!ObjectUtils.isEmpty(method)) {
            ReflectionUtils.invokeMethod(method, ticket, handStatus);
        } else {
            throw new SysException("未找到票据的 setTicketStatusInfo 方法");
        }
    }

    /**
     * 设置操作按钮
     *
     * @param ticket    票据对象
     * @param keyValues 操作按钮
     * @throws SysException 业务异常
     */
    public static void setOperateButton(@NotNull Object ticket, List<KeyValue> keyValues) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, SET_OPERATE_BUTTON_METHOD_NAME, List.class);
        if (!ObjectUtils.isEmpty(method)) {
            ReflectionUtils.invokeMethod(method, ticket, keyValues);
        } else {
            throw new SysException("未找到票据的 setOperateButton 方法");
        }
    }

    /**
     * 获取票据对象的 字段值
     *
     * @param ticket 票对象
     * @return 对象值
     */
    public static ApproveStatusEnum getApproveStatus(@NotNull Object ticket) throws SysException {
        Class<?> aClass = ticket.getClass();
        Method method = ReflectionUtils.findMethod(aClass, GET_APPROVE_STATUS_METHOD_NAME);
        if (!ObjectUtils.isEmpty(method)) {
            Object status = ReflectionUtils.invokeMethod(method, ticket);
            if (ObjectUtils.isEmpty(status)) {
                throw new SysException("未找到开立票据的 getApproveStatus 方法");
            }
            if (status instanceof Integer) {
                return ApproveStatusEnum.getStatus((Integer) status);
            } else {
                return ApproveStatusEnum.getStatus(Integer.valueOf(status.toString()));
            }
        } else {
            throw new SysException("未找到开立票据的 getApproveStatus 方法");
        }

    }


    /**
     * 获取票据id
     *
     * @param ticket 票据对象
     * @return 票据id
     * @throws SysException 当ticket没有getId方法时抛出异常
     */
    @Nullable
    public static String getId(@NotNull Object ticket) throws SysException {
        return getStringValue(ticket, GET_ID_METHOD_NAME, TICKET_OBJECT_NO_ID_METHOD_METHOD);
    }

    /**
     * 获取Integer类型返回值的方法
     *
     * @param ticket 票据对象
     * @return Integer类型值
     * @throws SysException 当ticket没有对应的获取Integer类型值的方法时抛出异常
     */
    @Nullable
    private static String getStringValue(@NotNull Object ticket, String methodName, SysExceptionEnum exceptionEnum) throws SysException {
        Class<?> clazz = ticket.getClass();
        Method method = ReflectionUtils.findMethod(clazz, methodName);
        if (method != null) {
            Object o = ReflectionUtils.invokeMethod(method, ticket);
            if (o instanceof String) {
                return (String) o;
            }
            return null;
        } else {
            throw SysExceptionFactory.createSysException(exceptionEnum);
        }
    }

    /**
     * 获取按钮权限是否存在
     * true 有权限
     * false 没权限
     *
     * @param session 按钮
     */
    public static boolean getButtonAuth(HttpSession session, String buttonCode) {
        //        session中的按钮权限集合key值：Constant.SESSION_BUTTON
        String buttonList = (String) session.getAttribute(Constant.SESSION_BUTTON);
        List<MenuInfo> menuInfos = JSON.parseArray(buttonList, MenuInfo.class);
        if (!CollectionUtils.isEmpty(menuInfos)) {
            List<String> collect = menuInfos.stream().map(MenuInfo::getMenuAction).distinct().collect(Collectors.toList());
            if (collect.contains(buttonCode)) {
                return true;
            }
        }
        return false;
    }
}
